# coding:utf-8

import json
from datetime import datetime, date

from flask import request, redirect, session, current_app, jsonify, url_for
from flask_restful import Resource, Api
from wechatpy.exceptions import WeChatOAuthException

from app.models import get_timestamp
from app.relationship.constant import FriendStatus
from app.relationship.models import MobileList
from app.wechat.models import WechatTemplate
from common.constant import GiveVoucherReason, VoucherStatType
from .. import db
from app.op.models import User, Area, WxUser
from app.op.constant import (
    UserType, UserLevel, UserActive, WxInviteState, UserCreditRule,
    TRIAL_VOUCHER_CNT)
from app.token import AuthToken
from app.ccws.models import create_outbound_mission, OutBoundRecord
from app.ccws.constant import CallReason
from common.wechat_util import generate_wechat_oauth
from .constant import TOKEN_TIMEOUT
from .views import AuthResource, Response
from .codes import SUCCESS, PARAMS_ILLEGAL
from .auth_schemas import login_schema
from .auth_codes import CAPTCHA_NOT_EXIST, CAPTCHA_NOT_MATCH
from .ip_utils import ip_util

api = Api()


@api.resource('/Login/handleLogin')
class NormalLoginResource(Resource):
    """
    created by chenhj at 2017/8/10
    使用验证码登录
    """
    def post(self):
        data, errors = login_schema.load(request.form)
        if errors:
            return Response(PARAMS_ILLEGAL.new_format_msg(list(errors.values())[0][0]))

        mobile = data['mobile']
        captcha = current_app.redis.get('captcha_{}'.format(mobile))
        if not captcha:
            return Response(CAPTCHA_NOT_EXIST)

        if captcha != data['sms_captcha']:
            return Response(CAPTCHA_NOT_MATCH)

        user = User.get_by_args(mobile=mobile)
        openid = session.get('openid')
        ip_info = ip_util.find(request.remote_addr)
        try:
            code = str(int(ip_info[2])) if ip_info.any() else '110000'
        except:
            code = '110000'

        city = Area.get_by_id(code[:4] + '00')
        prov = Area.get_by_id(code[:2] + '0000')

        if not user:
            try:
                user = User.create(
                    mobile=mobile,
                    nickname=data['mobile'],
                    type=UserType.ENGINEER.value,
                    level=UserLevel.LEVEL_2.value,
                    prov=prov.name,
                    city=city.name,
                    area_id=city.id
                )
            except:
                user = User.get_by_args(mobile=mobile)

            # 用户注册时，更新通讯的用户id
            MobileList.query.filter(
                MobileList.mobile == mobile,
                MobileList.followed_id.is_(None)
            ).update(
                dict(
                    followed_id=user.id,
                    status=FriendStatus.DEFAULT
                ),
                synchronize_session='fetch'
            )
            # add by zhouhl 2017-08-23
            # 如果是新用户，且没有openid，需要队列外呼邀请关注微信并绑定
            if not openid:
                tmp_outbound_record, err = create_outbound_mission(
                    user_id=user.id,
                    mobile=mobile,
                    call_reason=CallReason.INVITE_NEW_USER.value,
                    schedule_time=datetime.now(),
                )
                if tmp_outbound_record:
                    db.session.add(tmp_outbound_record)

        if not user.pack:
            user.type = UserType.ENGINEER.value
            user.level = UserLevel.LEVEL_2.value
            user.active = UserActive.ACTIVE.value

            # 新用户赠送代金券
            user.gift_bid_point()
            # 短信通知
            content = '已赠送您{}张价值200元无门槛代金券，立即打开“万屏汇”微信公众号免费抢单吧，过期将作废哦！回T退订'.format(
                TRIAL_VOUCHER_CNT
            )
            if content and user.mobile and current_app.wph_sms_producer:
                current_app.wph_sms_producer.send(
                    json.dumps({
                        'mobile': user.mobile,
                        'content': content,
                    })
                )
            # 触发代金券统计生产者
            current_app.common_producer.send(
                json.dumps(
                    dict(
                        backend='voucher_stat',
                        func='day_stat',
                        kwargs=dict(
                            voucher_stat_type=VoucherStatType.GRANT.value,
                            reason=GiveVoucherReason.SYSTEM_GIFT.value,
                            user_id=user.id,
                            stat_cnt=TRIAL_VOUCHER_CNT,
                        )
                    )
                )
            )

        if openid:
            # 成为工程商后拉新状态更新
            user.be_engineer_sms_handler()

            if user.bind_wx_openid == 0:
                # 拉新外呼更新是否拉新成功状态
                OutBoundRecord.update_invite_state(user.id)

            if not user.wx_openid and user.war_zone_id:
                # 入战区统计(非新用户), 新用户由于此时还没有战区, 因此要在消费者那边去入统计
                current_app.zone_stat_exchanger.exchange_send(json.dumps({
                    'attend_cnt': 1,
                    'war_zone_id': user.war_zone_id
                }))

            # 绑定openid
            user.wx_openid = openid
            user.bind_wx_openid = 1

            wxuser = WxUser.get_by_args(openid=openid)
            if wxuser and wxuser.invite_user_id and wxuser.invite_state == WxInviteState.NOT_BIND.value:
                wxuser.invite_state = WxInviteState.BINDED.value
                wxuser.certify_time = get_timestamp()
                wxuser.coordinates = data.get('coordinates', '')
                invite_user = User.get_by_id(wxuser.invite_user_id)
                wxuser.ip_address = request.remote_addr
                if invite_user:
                    invite_user.credit += UserCreditRule.INVITE.value

            # 推送新手指南
            url = 'https://mp.weixin.qq.com/s/P_rb1KkGzoSeYml75LJ9oA'
            template = WechatTemplate.get_by_args(code='freshman_guide')
            to_send_data = [{
                'openid': openid,
                'template_id': template.template_code,
                'data': json.loads(
                    template.content.replace(
                        'keyword1_value', user.mobile
                    ).replace(
                        'keyword2_value', date.today().strftime('%F')
                    )
                ),
                'url': url
            }]
            current_app.wechat_producer.send(json.dumps(to_send_data))

        resp = jsonify(Response(SUCCESS))
        resp.set_cookie('opc_token', AuthToken.generate_auth_token(TOKEN_TIMEOUT, user))
        return resp


@api.resource('/Login/handleLogin4Wx', endpoint='wx_login')
class WxLoginResource(Resource):
    """
    created by chenhj at 2017/8/10
    登录, 来自微信服务号
    """
    def get(self):
        """
        created by chenhj at 2017/8/10

        """
        redirect_url = request.args['redirect_url']

        # 判断该用户是否仍有有效cookie, 若有, 则更新cookie, 并直接登录, 不走微信第三方
        token = request.cookies.get('opc_token')
        user = AuthToken.verify_auth_token(token)
        if user and user.wx_openid:
            response = redirect(redirect_url)
            token = AuthToken.generate_auth_token(TOKEN_TIMEOUT, user)
            response.set_cookie('opc_token', token)
            return response

        args = request.args.copy()
        code = args.pop('code', None)
        args.pop('state', None)

        oauth = generate_wechat_oauth(
            url_for(request.endpoint, **args, _external=True)
        )
        if not code:
            return redirect(oauth.authorize_url)

        try:
            ret = oauth.fetch_access_token(code)
        except WeChatOAuthException:
            return redirect(oauth.authorize_url)
        openid = ret['openid']
        user = User.get_by_args(wx_openid=openid)
        if user:
            # 已绑定
            token = AuthToken.generate_auth_token(TOKEN_TIMEOUT, user)
        else:
            # 未绑定(即可能用user, 但没绑定微信)
            token = request.cookies.get('opc_token')
            user = AuthToken.verify_auth_token(token)
            if user:
                # 入战区统计
                current_app.zone_stat_exchanger.exchange_send(json.dumps({
                    'attend_cnt': 1,
                    'war_zone_id': user.war_zone_id
                }))
                # 如果已登录, 则自动绑定上
                user.wx_openid = openid
            else:
                # 未登录, 则跳转到绑定页
                session.setdefault('openid', openid)
                return redirect(redirect_url)
                # host = os.environ.get('wph_host')
                # redirect_url = urllib.parse.urljoin(host, 'user/loginform.html?login_bind=1')
                # return redirect(redirect_url)
        # 除了未绑定/未登录的情况外, 都跳转到 redirect_url
        response = redirect(redirect_url)
        response.set_cookie('opc_token', token)
        return response


@api.resource('/Login/handleLogout')
class LogoutResource(AuthResource):
    """
    created by chenhj at 2017/8/10
    登出
    """
    def post(self):
        # 解除用户绑定关系, 并清除token
        self.user.wx_openid = ''
        resp = jsonify(Response(SUCCESS))
        resp.delete_cookie('opc_token')
        return resp

    get = post
